<?php
/**
 * 文件操作
 *
 * 本包提供对文件操作功能
 *
 * @author    Garbin
 * @package    Library
 * @subpackage Ultity
 */

/**
 * 基础文件操作
 *
 * 该类为文件类，可提供基础的文件操作功能
 *
 * @author    Garbin
 */
class File extends Object
{
    protected $_path    = null;
    protected $_handle  = null;

    /**
     * 构造函数
     *
     * 实例化指定文件
     *
     * @author    Garbin
     * @access public
     * @param string $file_path 文件路径
     * @return void
     */
    public function __construct($file_path = null)
    {
        $this->_path = $file_path;
    }

    /**
     *  打开文件
     *
     *  以指定模式打开文件
     *
     *  @author    Garbin
     *  @param    string $model 打开模式
     *  @return    resource     返回文件句柄
     */
    public function open($model = 'wb')
    {
        $this->_handle = fopen($this->_path, $model);

        return $this->_handle;
    }

    /**
     *  写入内容
     *
     *  以指定模式写入内容至文件，默认以"wb"模式写入
     *
     *  @author    Garbin
     *  @param    string $contents 文件内容
     *  @param    string $model 写入模式(ab,wb...)
     *  @return    bool 成功写入返回true,反之为false
     */
    public function write($contents, $model = 'default')
    {
        switch ($model)
        {
            case 'default':
                $handle = is_resource($this->_handle) ?  $this->_handle : $this->open();
            break;
            default:
                $handle = fopen($this->_path, $model);
            break;
        }

        return fwrite($handle, $contents);
    }

    /**
     *  复制文件
     *
     *  复制文件至其他路径
     *
     *  @author    Garbin
     *  @param    string $path 目标路径
     *  @return    bool 成功返回true,反之为false
     */
    public function copy($path)
    {
        return copy($this->_path, $path);
    }

    /**
     *  移动文件
     *
     *  移动文件至目标路径
     *
     *  @author    Garbin
     *  @param    string    $path   目标路径
     *  @return    bool 成功返回true,反之为false
     */
    public function move($path)
    {
        $result = rename($this->_path, $path);
        if ($result)
        {
            $this->_path = $path;
        }

        return $result;
    }

    /**
     *  重命名
     *
     *  将文件名重命名
     *
     *  @author Garbin
     *  @param  string $name 目标文件名
     *  @return bool 成功返回true,反之false
     */
    public function rename($name)
    {
        if (!$name)
        {
            return;
        }
        $path = dirname($this->_path) . '/' . $name;

        return $this->move($path);
    }

    /**
     *  删除
     *
     *  删除该文件
     *
     *  @author Garbin
     *  @return bool 成功返回true,反之false
     */
    public function remove()
    {
        return @unlink($this->_path);
    }

    /**
     *  读取文件
     *
     *  读取文件所有内容，并返回
     *
     *  @author    Garbin
     *  @return    string 返回文件内容
     */
    public function read()
    {
        $contents = file_get_contents($this->_path);

        return $contents;
    }

    /**
     *  关闭
     *
     *  关闭文件句柄
     *
     *  @author    Garbin
     *  @return    void
     */
    public function close()
    {
        fclose($this->_handle);
    }

    /**
     *  锁定文件
     *
     *  取得一个文件锁
     *
     *  @author    Garbin
     *  @param    int $lock_model 锁类型
     *  @return    void
     */
    public function lock($lock_model = FILE_LOCK_EX)
    {
        flock($this->_handle, $lock_model);
    }
}

/**
 * 文本文件
 *
 * 提供对文本文件的操作功能
 *
 * @author    Garbin
 */
class TextFile extends File
{
    protected $_contents_array = array();

    public function open($model = 'wb')
    {
        parent::open($model);
        $this->_getContentsArray($this->_path);
    }

    /**
     *  取得文件的行数
     *
     *  获取该文件的行数
     *
     *  @author    Garbin
     *  @return    int 返回文件行数
     */
    public function count()
    {
        $count = count($this->_contents_array);

        return $count;
    }

    /**
     *  替换
     *
     *  查找并替换文件中的字符串，可使用普通方式或正则表达式替换，默认为普通方式替换
     *
     *  @author    Garbin
     *  @param     string $pattern 待替换字符串或模式
     *  @param     string $replace 用于替换的字符串或模式
     *  @param     string $model   替换方式，normal为普通模式，preg为正则表达式替换
     *  @return    void
     */
    public function replace($pattern, $replace, $model = 'normal')
    {
        if ($model == 'normal')
        {
            $func = 'str_replace';
        }
        elseif ($model == 'preg')
        {
            $func = 'preg_replace';
        }

        $this->write($func($pattern, $replace, $this->read()), 'w');
    }

    /**
     *  替换行
     *
     *  替换指定行的内容，默认为最后一行
     *
     *  @author    Garbin
     *  @param    string $contents 用于替换的内容
     *  @param    int $line_code   指定行号
     *  @return    void
     */
    public function replaceLine($contents, $line_code = -1)
    {
        $line_code = $this->_getLineCode($line_code);
        $this->_contents_array[$line_code] = $contents;
        $this->write(implode("\n", $this->_contents_array), 'w');
    }

    /**
     *  删除行
     *
     *  删除指定行，默认删除最后一行
     *
     *  @author    Garbin
     *  @param    int $line_code 指定行号
     *  @return    void
     */
    public function deleteLine($line_code = -1)
    {
        $line_code = $this->_getLineCode($line_code);
        unset($this->_contents_array[$line_code]);
        $this->write(implode("\n", $this->_contents_array), 'w');
    }

    /**
     *  新增行
     *
     *  在指定行后新增一行，默认在最后一行
     *
     *  @author    Garbin
     *  @param     string $contents 新增的行内容
     *  @param     int $pre_line 指定的行号，-1为最后一行
     *  @return    void
     */
    public function insertLine($contents, $pre_line = -1)
    {
        $pre_line = $this->_getLineCode($pre_line);
        $line_code= $pre_line + 1;
        $keys = array_keys($this->_contents_array);
        array_walk($keys, create_function('&$item', 'if($item > ' . $pre_line . ')$item = $item + 1;'));
        rsort($keys);
        foreach ($keys as $_k)
        {
            if ($_k > $line_code)
            {
                $this->_contents_array[$_k] = $this->_contents_array[$_k - 1];
            }
        }
        $this->_contents_array[$line_code] = $contents;
        $this->write(implode("\n", $this->_contents_array), 'w');

    }

    /**
     *  读取文件内容至数组
     *
     *  每一行为数组中的一项
     *
     *  @author    Garbin
     *  @return    void
     */
    protected function _getContentsArray()
    {
        $this->_contents_array = split("(\r|\r\n|\n){1}", file_get_contents($this->_path));
    }

    /**
     *  获取行号
     *
     *  @author    Garbin
     *  @param    int $line_code 指定的行号
     *  @return    int 行号
     */
    protected function _getLineCode($line_code)
    {
        if ($line_code == -1)
        {
            $line_code = $this->count();
        }

        return $line_code - 1;
    }
}
